Bruno Crotman
22/09/2019
…da maldição do erro operacional
PS.: ele não é Nobel…
…e ainda…
Meta final: que vários dos processos de análise de dados da empresa passem a ser feitos dentro do fluxo de trabalho do R.
Ao fim do curso o objetivo é que todos os fios da meada sejam puxados para que o aluno consiga continuar por si só usando a vasta documentação disponível.
Também amo o Excel, mas amo mais as seguintes vantagens:
Reprodutibilidade. Muito mais fácil refazer uma análise com código do que point and click
Menor risco operacional. A automatização é maior, a chance de erro na execução de um passo manual é nula
Menor risco de continuidade caso haja imprevistos com a equipe.
Maior flexibilidade. Virtualmente tudo é possível
Manutenção mais fácil
Controle de versão de forma profissional
Mais fácil do que parece
Ela é feita para lidar com dados
Comunidade de usuários gigante e cooperativa
Ferramentas poderosas para comunicação dos resultados, em documentos ou aplicações
Muitos pesquisadores em métodos quantitativos que estão no estado-da-arte publicam seus métodos em bibliotecas escritas em R
Prazeroso programar
É muito comum possuirmos dados gerados em planilhas ou em algum suporte de formarto estruturado.
Neste exemplo, temos planilhas deste formato formato especificado
Impacto da temperatura no consumo de energia elétrica
R é uma linguagem que é interpretada por um engine gratuito.
RStudio é o melhor ambiente de programação da linguagem R. A versão mais simples, que é totalmente funcional, é gratuita.
Na visualização padrão, ele oferece um console para execução de comandos e uma janela com a visualização dos environments, ou seja, das variáveis que ele guarda na sessão atual.
No console é possível executar comandos, como o que atribui valor a uma variável
Note que a atribuição é feita com <- e não com = como na maioria das linguagens.
Dica: o atalho alt + - gera o sinal de atribuição
Os comandos que não atribuem valor a uma variável são ecoados na tela
## [1] 3
Veja o [1] no console. O R considera que tudo é um vetor. É uma linguagem muito baseada em operações vetoriais. Isso facilita muito as coisas quando se lida com dados.
O console serve só para testes, aprendizado de novos comandos, debug, experiências etc.
Para as atividades mais comuns de análise de dados, e para que elas sejam reprodutíveis, é necessária a criação de scripts.
Eles são salvos em um arquivo de extensão “.r”
Atalhos de teclado: ctrl+enter (rodar linhas selecionadas), ctrl+shift+enter (rodar script), ctrl+1 (foco no script), ctrl+2 ** (foco no console), ctrl+shift+F10 ** (reiniciar R), ctrl+shift+C (comentar/descomentar bloco) …
Refactoring
Document outline
Pane: Files/Plots/Packages/Help/Viewer
Pane: Environment/History/Connections/Git
Jobs
Controle de versão integrado com o Github
Cheat sheets
Todo o material do curso está hospedado no Github, inclusive esta apresentação, escrita em RMarkdown.
Os exemplos de código, as imagens e os dados mostrados nesta apresentação estão inclusos no repositório do curso.
O repositório fica em github/crotman/cursoR.
Para baixar este repositório no RStudio, crie um projeto em File/New Project, do tipo Github e use o endereço do repositório: https://github.com/crotman/CursoR.git.
Todo material é disponibilizado sob a licença Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
Para o R, simplificando para o escopo deste curso, as variáveis “armazenam” os seguintes tipos:
## [1] 1 2 3 4 5 6 7 8 9 10
## [[1]]
## [1] "oi"
##
## [[2]]
## [1] 1
## # A tibble: 10 x 2
## col1 col2
## <int> <int>
## 1 1 11
## 2 2 12
## 3 3 13
## 4 4 14
## 5 5 15
## 6 6 16
## 7 7 17
## 8 8 18
## 9 9 19
## 10 10 20
## [1] 3
## [1] "sou o b"
Existe orientação a objetos no R, mas não está no escopo deste curso
Note que não há variáveis que armazenam dado escalar, como já vimos.
Dentre os vetores há:
vetores atômicos (seus elementos são do mesmo tipo primário)
listas (seus elementos, que são vetores atômicos, são de tipos primários diferentes)
Tipos de vetores
Fonte: Advanced R
Os vetores atômicos podem ser dos seguintes tipos:
Tipos primários
Fonte: Advanced R
## [1] FALSE
## [1] "integer"
## [1] "double"
## [1] 0.1
## [1] 1500
## [1] Inf
Uma das funções mais usadas do R é c(), que cria um vetor novo vetor combinando vetores.
## [1] 1 2 3
## [1] 1 2 3 4 5 6
## [1] 1.4 2.4 3.4 4.4 5.4 6.4 7.4 8.4 9.4
O operador : é usado para gerar um vetor com todos números que estão entre os operandos e são formados somando números inteiros ao primeiro operando.
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5
A função seq() é usada para criar um vetor de várias formas.
Numa das formas especifica-se o valor inicial, o valor final e o incremento entre elementos do vetor.
## [1] 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6
## [18] 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0 4.1 4.2 4.3
## [35] 4.4 4.5 4.6 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0
## [52] 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.2 7.3 7.4 7.5 7.6 7.7
## [69] 7.8 7.9 8.0 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 9.0 9.1 9.2 9.3 9.4
## [86] 9.5 9.6 9.7 9.8 9.9
Note que chamamos a função passando os parâmetros sem especificação de quais são eles. Eles são recebidos pela função dem específica.
Mas no R também é possível passar parâmetros de forma nomeada.
Clique em F1 enquanto tem o cursor em cima da função e veja a ordem dos parâmetros. Veja que outros parâmetros que não utilizamos. Podemos usar length.out ao invés de by:
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1.00 3.25 5.50 7.75 10.00
Outro parâmetro, along.with, deixa que criemos um vetor num intervalo determinado e o mesmo número de elementos do vetor passado por este parâmetro.
## [1] 20.00000 28.88889 37.77778 46.66667 55.55556 64.44444 73.33333
## [8] 82.22222 91.11111 100.00000
Valores faltantes ou desconecidos são representados por NA
## [1] 1 NA
O valor NA quase sempre contamina os cálculos
## [1] NA
mas…
## [1] 1
A exceção são expressões que dão sempre o mesmo resultado independentemente do valor da variável
## [1] 1
## [1] TRUE
## [1] FALSE
A melhor forma de testar se existe um valor NA é is.na
## [1] FALSE TRUE FALSE
As operações do R são vetoriais. Numa operação entre um vetor e um escalar, a operação com o escalar é aplicada a cada elemento do vetor
## [1] 2 4 6 8 10
## [1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
Numa operação com vetores do mesmo tamanho, os elementos são pareados
## [1] 1 4 9 16 25 36 49 64 81 100
Outro conceito importante é o de recycling.
Numa operação entre dois vetores de tamanhos diferentes, o vetor menor é repetido ciclicamente de forma a ficar com o mesmo tamanho do vetor maior.
Lembra que toda variável no R é um vetor?
Então… o escalar mostrado no primeiro código do slide anterior é um vetor de 1 elemento que sofre recycling
## [1] 1 4 3 8 5 12 7 16 9 20
Existem estruturas mais complexas na linguagem construídas a partir de vetores e listas.
Data Frame
Matrix
Array
Factor
Estruturas que representam datas
Objetos (no paradigma de orientação a objetos)
Vamos passar pelo Data Frame agora. Depois por Factor e objetos que representam Datas
Data Frames, e seu primo Tibble, são estruturas muito usadas em análises de dados feitas em R.
O dataframe consiste em um conjunto de vetores nomeados, com o mesmo número de elementos, que formam uma estrutura retangular, onde cada coluna é um vetor e cada linha n contém o n-ésimo elemento dos vetores.
É similar, em muitas características, a uma tabela de banco de dados.
Essa estrutura é chave no paradigma “Tidy” que usaremos com as bibliotecas Tidyverse
Tibble é uma adaptação do Data Frame para análise de dados. Discutir essas diferenças está fora do escopo do curso. Algumas diferenças serão citadas o longo do material e justificam o uso do Tibble.
df <-
data.frame(
nome = c("João", "Maria", "Zezinho", "Juquinha"),
idade = c(7, 8, 9, 10),
altura = c(10, 11)
)
df## nome idade altura
## 1 João 7 10
## 2 Maria 8 11
## 3 Zezinho 9 10
## 4 Juquinha 10 11
#tibble não aceita recycling em vetores de tamanho diferente de 1
tib <-
#try evita que o erro paralise toda a execução do script
try(
tibble(
nome = c("João", "Maria", "Zezinho", "Juquinha"),
idade = c(7, 8, 9, 10),
altura = c(10, 11)
)
)## Error : Tibble columns must have consistent lengths, only values of length one are recycled:
## * Length 2: Column `altura`
## * Length 4: Columns `nome`, `idade`
## Backtrace:
## x
## 1. +-rmarkdown::render("C:/dataquant/CursoR/Conteudo.Rmd", encoding = "UTF-8")
## 2. | \-knitr::knit(...)
## 3. | \-knitr:::process_file(text, output)
## 4. | +-base::withCallingHandlers(...)
## 5. | +-knitr:::process_group(group)
## 6. | \-knitr:::process_group.block(group)
## 7. | \-knitr:::call_block(x)
## 8. | \-knitr:::block_exec(params)
## 9. | +-knitr:::in_dir(...)
## 10. | \-knitr:::evaluate(...)
## 11. | \-evaluate::evaluate(...)
## 12. | \-evaluate:::evaluate_call(...)
## 13. | +-evaluate:::timing_fn(...)
## 14. | +-base:::handle(...)
## 15. | +-base::withCallingHandlers(...)
## 16. | +-base::withVisible(eval(expr, envir, enclos))
## 17. | \-base::eval(expr, envir, enclos)
## 18. | \-base::eval(expr, envir, enclos)
## 19. +-base::try(...)
## 20. | \-base::tryCatch(...)
## 21. | \-base:::tryCatchList(expr, classes, parentenv, handlers)
## 22. | \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]])
## 23. | \-base:::doTryCatch(return(expr), name, parentenv, handler)
## 24. \-tibble::tibble(...)
## 25. \-tibble:::lst_to_tibble(xlq$output, .rows, .name_repair, lengths = xlq$lengths)
## 26. \-tibble:::recycle_columns(x, .rows, lengths)
A linguagem oferece comandos de controle de fluxo similares aos de outras linguagens.
Podemos dividir os comandos de controle de fluxo em dois tipos:
choices: execução alternativa de comandos
loops: execução repetida de comandos
if, ifelseO comando if funciona para um valor lógico escalar
## [1] "2 mais 2 são 4"
Note o operador de comparação == e não =
A função if_else (da biblioteca dplyr) funciona de vetorial. if_else é mais rápida que a função ifelse da biblioteca base, mas só aceita argumentos de mesmo tipo no segundo e terceiro parâmetros
jogo_do_pim_silvio_santos <- if_else(
condition = 1:40 %% 4 == 0 ,
true = "PIM",
false = as.character(1:40)
)
jogo_do_pim_silvio_santos## [1] "1" "2" "3" "PIM" "5" "6" "7" "PIM" "9" "10" "11"
## [12] "PIM" "13" "14" "15" "PIM" "17" "18" "19" "PIM" "21" "22"
## [23] "23" "PIM" "25" "26" "27" "PIM" "29" "30" "31" "PIM" "33"
## [34] "34" "35" "PIM" "37" "38" "39" "PIM"
Note o operador %% e a função de coerção de tipo as.character
switch e case_whenA cláusula switch e a função dplyr::case_when evitam que o programador tenha que criar muitos if else aninhados
## [1] "começa com b"
Note que a condição vai sendo testada na ordem e stop gera um erro
case_when serve ao caso vetorial
## [1] "1" "par" "3" "par" "5" "par" "7"
## [8] "par" "9" "dezena" "11" "par" "13" "par"
## [15] "15" "par" "17" "par" "19" "dezena" "21"
## [22] "par" "23" "par" "25" "par" "27" "par"
## [29] "29" "dezena" "31" "par" "33" "par" "35"
## [36] "par" "37" "par" "39" "dezena"
A cláusula de loop mais usada e mais versátil é for
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
As cláusulas next e break modificam o comportamento, respectivamente caminhando direto para a próxima iteração e saindo do for
## [1] 1
## [1] 3
## [1] 5
## [1] 1
Vamos ver que quase sempre é desnecessário usar loop para as tarefas que vamos executar.
O caráter vetorial da linguagem, aliado a funcionalidades das bibliotecas, faz com que a grande maioria dos loops sejam desnecessários.
O código fica mais limpo e expressivo e mais rápido. Às vezes MUITO mais rápido. Isso ocorre por motivos além do escopo do curso (alocação de memória, código interpretado x código compilado em C++ etc.)
O código abaixo usa loop e programação funcional, respectivamente. Programação funcional será abordada posteriormente no material.
com_loop <- function(n){
x <- integer()
for (i in 1:n){
x <- c(x, i^2)
}
x
}
#programação funcional: aprenderemos posteriomente
sem_loop <- function(n){
x <- 1:n %>%
map_dbl(function(x){x^2})
x
}Abaixo as três formas de fazer a mesma conta que terão a performance avaliada
## [1] 1 4 9 16 25
## [1] 1 4 9 16 25
## [1] 1 4 9 16 25
A biblioteca bench oferece funções ótimas para avaliar a performance de pedaços pequenos de código.
resultados_perf <- mark(
sem_loop(1e4),
com_loop(1e4),
(1:1e4)^2
)
#aprenderemos o que é %>% e select() posteriormente
resultados_perf %>%
select(expression, min, median, `itr/sec` )## # A tibble: 3 x 4
## expression min median `itr/sec`
## <bch:expr> <bch:tm> <bch:tm> <dbl>
## 1 sem_loop(10000) 6.45ms 6.97ms 130.
## 2 com_loop(10000) 92.95ms 113.7ms 7.29
## 3 (1:10000)^2 16us 17.3us 22478.
Monty Hall era uma espécie de Sílvio Santos juvenil (sub 80) americano.
Um dos seus jogos consistia em mostrar três portas ao otár… (ops) convidado. Em uma delas tem um carro.
Antes do resultado, o apresentador revela uma das portas e pergunta se o convidado que trocar a escolha.
O que vocês acham? Melhor trocar, manter a escolha original ou tanto faz?
Note o que há de interessante no código (comentado)
set.seed(88)
joga_monty_hall <- function(troca){
portas <- 1:3
#sample() sorteia elementos com ou sem reposição
porta_carro <- sample(portas, size = 1, replace = FALSE)
primeira_escolha <- 1
#Seleção negativa (retirando elementos)
portas_pra_revelar <- portas[-c(porta_carro, primeira_escolha)]
porta_revelada <- sample( c(portas_pra_revelar, portas_pra_revelar ), 1)
if(troca){
escolha <- portas[-c(primeira_escolha, porta_revelada)]
}
else{
escolha <- primeira_escolha
}
escolha == porta_carro
}
n <- 1000
#replicate executa múltiplas vezes um comando e armazena os resultados em uma estruturaúnica
troca <- replicate(n = n, joga_monty_hall(troca = TRUE))
fica <- replicate(n = n, joga_monty_hall(troca = FALSE))Resultados:
## [1] 0.675
## [1] 0.323
Vamos ver… mas dá pra simular sem saber quase nada.
Vamos usar uma das funções da família r<familia de distribuição de prob>(). Neste caso, a rbinom, que simula a distribução binomial (aquela que equivale ao evento de jogar n moedas (ou alguma coisa com dois lados) para cima e ver quantas deram cara).
n_simul <- 10000
n_questoes <- 240
min_aprovacao <- 0.6
n_aprovado <- 240 * min_aprovacao
prob_questao <- 0.2
acertos <- rbinom(n = n_simul, size = n_questoes, prob = prob_questao )
sum(acertos >= n_aprovado)/n_simul ## [1] 0
A chance é praticamente nula.
Na verdade, a grande massa da distribuição fica muito distante.
dado <- enframe(acertos/n_questoes)
mostra_chances <- function(acertos, n_questoes){
ggplot(enframe(acertos/n_questoes)) +
geom_density( aes(x = value)) +
scale_x_continuous(
labels = percent_format(accuracy = 1),
limits = c(0,1),
breaks = seq(0, 1, 0.1)
) +
labs(x ="% Acertos") +
geom_vline(xintercept = min_aprovacao, color = "red") +
theme_light()
}
mostra_chances(acertos, n_questoes)O exemplo anterior era muito simplista: ninguém chuta tudo.
Imagine que sabemos qual a chance de aparecer uma pergunta onde podemos descartar 0 alternativas, a chance de uma onde descartamos 1 e assim por diante.
#definindo a chance podermos eliminar 0, 1, 2, ... 4 alternativas
fracao_eliminar_questoes <- c( 0.1, 0.1, 0.2, 0.25 , 0.35 )
#definindo o número de questões
n_questoes_cada_elimina <- t(rmultinom(n_simul, size = n_questoes, fracao_eliminar_questoes))
probs_quando_elimina <- 1/(5:1)
acertos_concatenados <-
rbinom(
n = n_simul * 5 ,
size = as.vector(t(n_questoes_cada_elimina)),
prob = probs_quando_elimina
)## [,1] [,2] [,3] [,4] [,5]
## [1,] 23 24 50 47 96
## [2,] 24 17 48 64 87
## [3,] 23 30 43 56 88
## [4,] 20 25 51 52 92
## [1] 4 6 17 25 96 4 3 13 34 87 6 5 13 36 88 4 9 17 25 92
## [,1] [,2] [,3] [,4] [,5]
## [1,] 4 6 17 25 96
## [2,] 4 3 13 34 87
## [3,] 6 5 13 36 88
## [4,] 4 9 17 25 92
## [5,] 6 5 11 30 92
## [1] 0.3131
Dentro de todo o hype envolvendo Data Science, surgem as buzz words mais mirabolantes: machine learning, AI, Deep Learning…
Tudo isso é legal, mas a habilidade de preparar os dados para os modelos, preparar os hiperparâmetros e especificações alternativas ainda melhora muito a análise. Anote mais uma buzz word: FEATURE ENGINEERING
A agilidade de se tentar abordagens alterativas com os dados cresce muito quando dominamos a arte de manipular os dataframes. Por isso o peso grande dado neste curso.
Arrumar os dados de forma que as linhas sejam eventos e as colunas sejam atributos do evento ajuda muito a rodar modelos e construir visualizações eficientemente.
O que é o evento e o que é o atributo pode variar até para diferentes usos do mesmo dado. Mas a prática ajuda a determinar isso.
%>%)Normalmente os tratamentos de dados são feitos em múltiplos passos encadeados:
## # A tibble: 6 x 6
## country continent year lifeExp pop gdpPercap
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afghanistan Asia 1952 28.8 8425333 779.
## 2 Afghanistan Asia 1957 30.3 9240934 821.
## 3 Afghanistan Asia 1962 32.0 10267083 853.
## 4 Afghanistan Asia 1967 34.0 11537966 836.
## 5 Afghanistan Asia 1972 36.1 13079460 740.
## 6 Afghanistan Asia 1977 38.4 14880372 786.
Vamos imaginar que queremos a média de PIB per capita por continente em 2007.
Note quanto código desnecessário há nestas linhas: variáveis que não precisavam ser nomeadas nem passadas explicitamente como parâmetro.
Este código desnecessário causa fadiga no programador e confunde o próprio programador e o leitor posterior do código.
#vamos cobrir essas funções de tratamento posteriormente
gapminder_07 <- filter(gapminder, year == 2007)
gapminder_07_group_continente <- group_by(gapminder_07, continent)
gapminder_media_gdp_continente <- summarise(
gapminder_07_group_continente, media_gdp = sum(gdpPercap * pop)/sum(pop)
)
resultado <- arrange(gapminder_media_gdp_continente, desc(media_gdp))
resultado## # A tibble: 5 x 2
## continent media_gdp
## <fct> <dbl>
## 1 Oceania 32885.
## 2 Europe 25244.
## 3 Americas 21603.
## 4 Asia 5432.
## 5 Africa 2561.
%>%) (cont.)O operador pipe %>% faz o seguinte:
x %>% y(z) = y(x,z)
Ou seja, o primeiro operando é enfiado como primeiro parâmetro da função que está no segundo operando.
Isso faz com que possamos escrever o código anterior assim:
resultado <- gapminder %>%
filter(year == 2007) %>%
group_by(continent) %>%
summarise(
media_gdp = sum(gdpPercap * pop) / sum(pop)
) %>%
arrange(desc(media_gdp))
resultado## # A tibble: 5 x 2
## continent media_gdp
## <fct> <dbl>
## 1 Oceania 32885.
## 2 Europe 25244.
## 3 Americas 21603.
## 4 Asia 5432.
## 5 Africa 2561.
Note que agora podemos interpretar o código facilmente como uma série de comandos de tratamento em cima dos dados.
Não é por coincidência que as funções de tratamento das bibliotecas tidyverse que veremos adiante são verbos e recebem os dados como primeiro parâmetro.
Agora o mais importante de tudo: O ATALHO PARA O %>% É CTRL + SHIFT + M
CRAN é o repositório de bibliotecas mantido pelo R com contribuição de populares.
Além de funcionalidades estatísticas e funcionalidades para lidar com dados, há dados e funcionalidades para buscar dados online.
Usaremos várias das bases como exemplo.
A primeira é a do Banco Mundial, muito rica para quem gosta de dados socioeconômicos
Para acessar um indicador precisamos achá-lo na base de indicadores com a função wbsearch()
#pattern é uma expressão regular. \\ serve para dizer que "(" é mesmo "("
#e não o ( usado nas operações de expressão regular (fora do escopo do curso)
indicadores <- wbsearch(pattern = "GINI index \\(World Bank estimate\\)")
indicadores## indicatorID indicator
## 1348 SI.POV.GINI GINI index (World Bank estimate)
Sabendo o ID do indicador, podemos consultá-lo com a função wb()
#mrv é most recent values. Pode ser usado para buscar os n valores mais recentes
gini = wb(indicator = "SI.POV.GINI", mrv= 10, POSIXct = TRUE)
head(gini)## iso3c date value indicatorID indicator iso2c
## 486 ALB 2012 29.0 SI.POV.GINI GINI index (World Bank estimate) AL
## 490 ALB 2008 30.0 SI.POV.GINI GINI index (World Bank estimate) AL
## 497 DZA 2011 27.6 SI.POV.GINI GINI index (World Bank estimate) DZ
## 530 AGO 2008 42.7 SI.POV.GINI GINI index (World Bank estimate) AO
## 541 ARG 2017 40.6 SI.POV.GINI GINI index (World Bank estimate) AR
## 542 ARG 2016 42.4 SI.POV.GINI GINI index (World Bank estimate) AR
## country date_ct granularity
## 486 Albania 2012-01-01 annual
## 490 Albania 2008-01-01 annual
## 497 Algeria 2011-01-01 annual
## 530 Angola 2008-01-01 annual
## 541 Argentina 2017-01-01 annual
## 542 Argentina 2016-01-01 annual
dplyr é uma das bibliotecas que fqzem parte do conjunto tidyverse
A função select() é usada para selecionar colunas do dataframe/tibble
## Observations: 684
## Variables: 9
## $ iso3c <chr> "ALB", "ALB", "DZA", "AGO", "ARG", "ARG", "ARG", "...
## $ date <chr> "2012", "2008", "2011", "2008", "2017", "2016", "2...
## $ value <dbl> 29.0, 30.0, 27.6, 42.7, 40.6, 42.4, 41.4, 41.0, 41...
## $ indicatorID <chr> "SI.POV.GINI", "SI.POV.GINI", "SI.POV.GINI", "SI.P...
## $ indicator <chr> "GINI index (World Bank estimate)", "GINI index (W...
## $ iso2c <chr> "AL", "AL", "DZ", "AO", "AR", "AR", "AR", "AR", "A...
## $ country <chr> "Albania", "Albania", "Algeria", "Angola", "Argent...
## $ date_ct <date> 2012-01-01, 2008-01-01, 2011-01-01, 2008-01-01, 2...
## $ granularity <chr> "annual", "annual", "annual", "annual", "annual", ...
## country date value iso3c
## 486 Albania 2012 29.0 ALB
## 490 Albania 2008 30.0 ALB
## 497 Algeria 2011 27.6 DZA
## 530 Angola 2008 42.7 AGO
## 541 Argentina 2017 40.6 ARG
## 542 Argentina 2016 42.4 ARG
É possível usar a seleção negativa assim como fizemos com vetores
## country date value
## 486 Albania 2012 29.0
## 490 Albania 2008 30.0
## 497 Algeria 2011 27.6
## 530 Angola 2008 42.7
## 541 Argentina 2017 40.6
## 542 Argentina 2016 42.4
Algumas funções helpers nos ajudam a usar a função select e são muito úteis para tratamentos mais elaborados.
Pra mostrar mais funcionalidades da função select, vamos usar uma base com dados eleitorais brasileiros, que retorna mais colunas
## Processing the data...
## Done.
## Observations: 29,113
## Variables: 58
## $ DATA_GERACAO <chr> "15/11/2018", "15/11/2018", "15...
## $ HORA_GERACAO <time> 20:03:47, 20:03:47, 20:03:47, ...
## $ ANO_ELEICAO <dbl> 2018, 2018, 2018, 2018, 2018, 2...
## $ COD_TIPO_ELEICAO <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2...
## $ NOME_TIPO_ELEICAO <chr> "ELEIÇÃO ORDINÁRIA", "ELEIÇÃO O...
## $ NUM_TURNO <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
## $ COD_ELEICAO <dbl> 297, 297, 297, 297, 297, 297, 2...
## $ DESCRICAO_ELEICAO <chr> "Eleições Gerais Estaduais 2018...
## $ DATA_ELEICAO <chr> "07/10/2018", "07/10/2018", "07...
## $ ABRANGENCIA <chr> "ESTADUAL", "ESTADUAL", "ESTADU...
## $ SIGLA_UF <chr> "AC", "AC", "AC", "AC", "AC", "...
## $ SIGLA_UE <chr> "AC", "AC", "AC", "AC", "AC", "...
## $ DESCRICAO_UE <chr> "ACRE", "ACRE", "ACRE", "ACRE",...
## $ CODIGO_CARGO <dbl> 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7...
## $ DESCRICAO_CARGO <chr> "DEPUTADO ESTADUAL", "DEPUTADO ...
## $ SEQUENCIAL_CANDIDATO <dbl> 10000601020, 10000603904, 10000...
## $ NUMERO_CANDIDATO <dbl> 14088, 31100, 45456, 35193, 173...
## $ NOME_CANDIDATO <chr> "ANA ISLA ARRUDA FREITAS", "MAR...
## $ NOME_URNA_CANDIDATO <chr> "ANA FREITAS", "LORA DO COMERCI...
## $ NOME_SOCIAL_CANDIDATO <chr> "#NULO#", "#NULO#", "#NULO#", "...
## $ CPF_CANDIDATO <chr> "93353405291", "63049112204", "...
## $ EMAIL_CANDIDATO <chr> "ANAFREITAS.AIF@GMAIL.COM", "JU...
## $ COD_SITUACAO_CANDIDATURA <dbl> 12, 12, 12, 12, 12, 12, 12, 12,...
## $ DES_SITUACAO_CANDIDATURA <chr> "APTO", "APTO", "APTO", "APTO",...
## $ COD_DETALHE_SITUACAO_CAND <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2...
## $ DES_DETALHE_SITUACAO_CAND <chr> "DEFERIDO", "DEFERIDO", "DEFERI...
## $ TIPO_AGREMIACAO <chr> "PARTIDO ISOLADO", "COLIGAÇÃO",...
## $ NUMERO_PARTIDO <dbl> 14, 31, 45, 35, 17, 27, 13, 13,...
## $ SIGLA_PARTIDO <chr> "PTB", "PHS", "PSDB", "PMB", "P...
## $ NOME_PARTIDO <chr> "PARTIDO TRABALHISTA BRASILEIRO...
## $ CODIGO_LEGENDA <dbl> 10000050036, 10000050109, 10000...
## $ NOME_COLIGACAO <chr> "PARTIDO ISOLADO", "FORÇA DA UN...
## $ COMPOSICAO_LEGENDA <chr> "PTB", "PMB / PHS", "PSDB / DEM...
## $ CODIGO_NACIONALIDADE <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
## $ DESCRICAO_NACIONALIDADE <chr> "BRASILEIRA NATA", "BRASILEIRA ...
## $ SIGLA_UF_NASCIMENTO <chr> "AC", "AC", "AC", "AC", "AC", "...
## $ CODIGO_MUNICIPIO_NASCIMENTO <dbl> -3, -3, -3, -3, -3, -3, -3, -3,...
## $ NOME_MUNICIPIO_NASCIMENTO <chr> "RIO BRANCO", "TARAUCÁ", "FEIJÓ...
## $ DATA_NASCIMENTO <chr> "12/08/1987", "10/02/1976", "12...
## $ IDADE_DATA_POSSE <dbl> 31, 42, 44, 47, 31, 26, 38, 39,...
## $ NUM_TITULO_ELEITORAL_CANDIDATO <chr> "005491592429", "001633372461",...
## $ CODIGO_SEXO <dbl> 4, 4, 4, 2, 2, 2, 2, 2, 2, 4, 2...
## $ DESCRICAO_SEXO <chr> "FEMININO", "FEMININO", "FEMINI...
## $ COD_GRAU_INSTRUCAO <dbl> 4, 3, 6, 8, 7, 6, 8, 8, 7, 8, 8...
## $ DESCRICAO_GRAU_INSTRUCAO <chr> "ENSINO FUNDAMENTAL COMPLETO", ...
## $ CODIGO_ESTADO_CIVIL <dbl> 1, 1, 3, 3, 3, 1, 3, 3, 1, 3, 3...
## $ DESCRICAO_ESTADO_CIVIL <chr> "SOLTEIRO(A)", "SOLTEIRO(A)", "...
## $ CODIGO_COR_RACA <chr> "03", "01", "01", "03", "03", "...
## $ DESCRICAO_COR_RACA <chr> "PARDA", "BRANCA", "BRANCA", "P...
## $ CODIGO_OCUPACAO <dbl> 581, 169, 999, 297, 999, 999, 2...
## $ DESCRICAO_OCUPACAO <chr> "DONA DE CASA", "COMERCIANTE", ...
## $ DESPESA_MAX_CAMPANHA <dbl> 0, -1, 0, -1, 0, 0, 0, 0, -1, 0...
## $ COD_SIT_TOT_TURNO <dbl> 5, 5, 5, 5, 5, 4, 3, 5, 5, 4, 2...
## $ DESC_SIT_TOT_TURNO <chr> "SUPLENTE", "SUPLENTE", "SUPLEN...
## $ SITUACAO_REELEICAO <chr> "N", "N", "N", "N", "N", "N", "...
## $ SITUACAO_DECLARAR_BENS <chr> "N", "N", "S", "S", "N", "N", "...
## $ NUMERO_PROTOCOLO_CANDIDATURA <dbl> -1, -1, -1, -1, -1, -1, -1, -1,...
## $ NUMERO_PROCESSO <chr> "06002996220186010000", "060045...
candidatos_select <- candidatos %>%
select(ends_with("candidato"))
datatable(head(candidatos_select))A função helper num_range ajuda a encontrar colunas do tipo prefixo_n. Isso é muito comum em bases de dados
A biblioteca worldmet retorna dados de estações meteorológicas espalhadas pelo planeta
Primeiro é necessário encontrar o código da base desejada
A função abaixo retorna os dados de uma estação. Veja que alguns campos têm um sufixo _n
dados_heathrow <- importNOAA(code = "037720-99999", year = 2019,
precip = TRUE, PWC = FALSE, parallel = TRUE)
glimpse(dados_heathrow)## Observations: 6,166
## Variables: 26
## $ date <dttm> 2019-01-01 00:00:00, 2019-01-01 01:00:00, 2019-01...
## $ usaf <chr> "037720", "037720", "037720", "037720", "037720", ...
## $ wban <chr> "99999", "99999", "99999", "99999", "99999", "9999...
## $ code <chr> "037720-99999", "037720-99999", "037720-99999", "0...
## $ station <chr> "HEATHROW", "HEATHROW", "HEATHROW", "HEATHROW", "H...
## $ lat <dbl> 51.47967, 51.47967, 51.47967, 51.47967, 51.47967, ...
## $ lon <dbl> -0.4573333, -0.4573333, -0.4573333, -0.4573333, -0...
## $ elev <dbl> 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25...
## $ wd <dbl> 283.706052, 286.994553, 290.000000, 290.000000, 27...
## $ ws <dbl> 3.266667, 3.433333, 4.100000, 3.433333, 3.266667, ...
## $ ceil_hgt <dbl> 657.3333, 667.3333, 728.0000, 768.0000, 778.3333, ...
## $ visibility <dbl> 22000, 28000, 45000, 45000, 35000, 35000, 28000, 2...
## $ air_temp <dbl> 8.666667, 8.933333, 9.000000, 9.000000, 7.966667, ...
## $ dew_point <dbl> 4.9333333, 4.9666667, 4.7666667, 4.8000000, 4.8000...
## $ atmos_pres <dbl> 1034.8, 1034.5, 1034.6, 1034.5, 1034.4, 1033.9, 10...
## $ RH <dbl> 77.67802, 76.42835, 75.06237, 75.23079, 80.81974, ...
## $ cl_1 <dbl> 7.666667, 8.000000, 7.666667, 8.000000, 7.666667, ...
## $ cl_1_height <dbl> 657.3333, 667.3333, 728.0000, 768.0000, 778.3333, ...
## $ cl_2 <dbl> 8.000000, NA, 8.000000, NA, NA, NA, 7.000000, 7.00...
## $ cl_2_height <dbl> 792, NA, 914, NA, NA, NA, 1006, 1036, NA, 720, 121...
## $ cl_3 <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
## $ cl_3_height <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
## $ precip_12 <dbl> NA, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA, NA, NA,...
## $ precip_6 <dbl> 0, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA, NA, 0, N...
## $ cl <dbl> 8.000000, 8.000000, 8.000000, 8.000000, 7.666667, ...
## $ precip <dbl> NA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
A função helper num_range ajuda a selecionar essas colunas com prefixo comum e um sufixo numérico
dados_heathrow_select <- dados_heathrow %>%
select(
date,
num_range("cl_", 1:3 ),
num_range("precip_", c(6, 12))
)
head(dados_heathrow_select)## # A tibble: 6 x 6
## date cl_1 cl_2 cl_3 precip_6 precip_12
## <dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2019-01-01 00:00:00 7.67 8 NA 0 NA
## 2 2019-01-01 01:00:00 8 NA NA NA NA
## 3 2019-01-01 02:00:00 7.67 8 NA NA NA
## 4 2019-01-01 03:00:00 8 NA NA NA NA
## 5 2019-01-01 04:00:00 7.67 NA NA NA NA
## 6 2019-01-01 05:00:00 6 NA NA NA NA
Outra função útil é a everything, que ajuda, por exemplo, a passar algumas colunas para o início do tibble.
dados_heathrow_select <- dados_heathrow %>%
select(
date,
air_temp,
everything()
)
glimpse(dados_heathrow_select)## Observations: 6,166
## Variables: 26
## $ date <dttm> 2019-01-01 00:00:00, 2019-01-01 01:00:00, 2019-01...
## $ air_temp <dbl> 8.666667, 8.933333, 9.000000, 9.000000, 7.966667, ...
## $ usaf <chr> "037720", "037720", "037720", "037720", "037720", ...
## $ wban <chr> "99999", "99999", "99999", "99999", "99999", "9999...
## $ code <chr> "037720-99999", "037720-99999", "037720-99999", "0...
## $ station <chr> "HEATHROW", "HEATHROW", "HEATHROW", "HEATHROW", "H...
## $ lat <dbl> 51.47967, 51.47967, 51.47967, 51.47967, 51.47967, ...
## $ lon <dbl> -0.4573333, -0.4573333, -0.4573333, -0.4573333, -0...
## $ elev <dbl> 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25...
## $ wd <dbl> 283.706052, 286.994553, 290.000000, 290.000000, 27...
## $ ws <dbl> 3.266667, 3.433333, 4.100000, 3.433333, 3.266667, ...
## $ ceil_hgt <dbl> 657.3333, 667.3333, 728.0000, 768.0000, 778.3333, ...
## $ visibility <dbl> 22000, 28000, 45000, 45000, 35000, 35000, 28000, 2...
## $ dew_point <dbl> 4.9333333, 4.9666667, 4.7666667, 4.8000000, 4.8000...
## $ atmos_pres <dbl> 1034.8, 1034.5, 1034.6, 1034.5, 1034.4, 1033.9, 10...
## $ RH <dbl> 77.67802, 76.42835, 75.06237, 75.23079, 80.81974, ...
## $ cl_1 <dbl> 7.666667, 8.000000, 7.666667, 8.000000, 7.666667, ...
## $ cl_1_height <dbl> 657.3333, 667.3333, 728.0000, 768.0000, 778.3333, ...
## $ cl_2 <dbl> 8.000000, NA, 8.000000, NA, NA, NA, 7.000000, 7.00...
## $ cl_2_height <dbl> 792, NA, 914, NA, NA, NA, 1006, 1036, NA, 720, 121...
## $ cl_3 <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
## $ cl_3_height <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
## $ precip_12 <dbl> NA, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA, NA, NA,...
## $ precip_6 <dbl> 0, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA, NA, 0, N...
## $ cl <dbl> 8.000000, 8.000000, 8.000000, 8.000000, 7.666667, ...
## $ precip <dbl> NA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
mutate()A função mutate é usada para criar novas colunas no tibble
Notando que a coluna DATA_ELEICAO é um caracter, vamos criar uma coluna de tipo data.
## [1] "character"
O jeito mais fácil de fazer isso é usando uma das funções da biblioteca lubridate que veremos em detalhes em seguida
candidatos_com_data <- candidatos %>%
mutate(DATA_ELEICAO_TIPO_DATA = dmy(DATA_ELEICAO)) %>%
select(DATA_ELEICAO, DATA_ELEICAO_TIPO_DATA)
head(candidatos_com_data)## # A tibble: 6 x 2
## DATA_ELEICAO DATA_ELEICAO_TIPO_DATA
## <chr> <date>
## 1 07/10/2018 2018-10-07
## 2 07/10/2018 2018-10-07
## 3 07/10/2018 2018-10-07
## 4 07/10/2018 2018-10-07
## 5 07/10/2018 2018-10-07
## 6 07/10/2018 2018-10-07
É possível substituir a um campo existente
candidatos_com_data <- candidatos %>%
mutate(DATA_ELEICAO = dmy(DATA_ELEICAO)) %>%
select(DATA_ELEICAO)
head(candidatos_com_data)## # A tibble: 6 x 1
## DATA_ELEICAO
## <date>
## 1 2018-10-07
## 2 2018-10-07
## 3 2018-10-07
## 4 2018-10-07
## 5 2018-10-07
## 6 2018-10-07
mutate()funções derivadas da mutate possibilitam a alteração de várias colunas ao mesmo tempo, usando os mesmos helpers que jã vimos para a select e uma função à escolha
candidatos_com_data <- candidatos %>%
mutate_at(vars(starts_with("DATA_")), dmy ) %>%
select(starts_with("DATA_"))
head(candidatos_com_data)## # A tibble: 6 x 3
## DATA_GERACAO DATA_ELEICAO DATA_NASCIMENTO
## <date> <date> <date>
## 1 2018-11-15 2018-10-07 1987-08-12
## 2 2018-11-15 2018-10-07 1976-02-10
## 3 2018-11-15 2018-10-07 1974-08-12
## 4 2018-11-15 2018-10-07 1971-09-09
## 5 2018-11-15 2018-10-07 1988-02-01
## 6 2018-11-15 2018-10-07 1992-11-11
mutate() (cont.):Outras funções úteis são as que fazem operações acumuladas e as operações de lag() e lead()
##
## BETS-package: Found 33 out of 18706 time series.
## # A tibble: 33 x 7
## code description unit periodicity start last_value source
## <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 1 Exchange rate - Free~ c.m.u~ D 28/11~ 26/03/2018 Sisbac~
## 2 10813 Exchange rate - Free~ c.m.u~ D 28/11~ 03/05/2018 Sisbac~
## 3 11753 Real effective excha~ Index M 31/01~ mar/2018 BCB-DS~
## 4 11758 Real effective excha~ Index M 31/01~ mar/2018 BCB-DS~
## 5 11763 Real effective excha~ Index M 31/01~ mar/2018 BCB-DS~
## 6 11768 Real effective excha~ Index M 31/01~ mar/2018 BCB-DS~
## 7 17887 Exchange rate (perio~ US$/c~ M 31/01~ nov/2016 IMF-IFS
## 8 17888 Exchange rate (perio~ US$/c~ M 31/01~ nov/2016 IMF-IFS
## 9 18441 Exchange rate (end o~ US$/c~ M 31/01~ nov/2016 IMF-IFS
## 10 18442 Exchange rate (end o~ US$/c~ M 31/01~ nov/2016 IMF-IFS
## # ... with 23 more rows
No código abaixo, calculamos o retorno da série, a volatilidade histórica e a volatilidade EWMA
dolar <- BETSget(1)
dolar_com_vol <- dolar %>%
filter(date > ymd("1994-07-01")) %>%
arrange(date) %>%
mutate(
retorno = (value - lag(value))/value,
retorno_quad = retorno^2,
dia = row_number(),
fator_ewma = (1/0.94)^dia*1e-20
) %>%
filter(!is.na(retorno)) %>%
mutate(vol = sqrt(cumvar(retorno)) * sqrt(252) ) %>%
mutate(vol_ewma = sqrt(cumsum(retorno_quad * fator_ewma)/cumsum(fator_ewma)) * sqrt(252) ) %>%
rename(dolar = value) %>%
select(
date,
dolar,
retorno,
vol,
vol_ewma
)
datatable(dolar_com_vol) %>%
formatPercentage(c("retorno", "vol", "vol_ewma"), 2)dolar_ajeitado <- dolar_com_vol %>%
gather(variavel, valor, - date)
dolar_ajeitado %>%
ggplot() +
geom_line(aes(x = date, y = valor)) +
facet_grid( variavel ~ . , scales = "free") +
theme_light() arrange():A função arrange serve para ordenar o tibble.
## # A tibble: 6 x 26
## date usaf wban code station lat lon elev wd
## <dttm> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 2019-01-01 00:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 284.
## 2 2019-01-01 01:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 287.
## 3 2019-01-01 02:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 290
## 4 2019-01-01 03:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 290
## 5 2019-01-01 04:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 276.
## 6 2019-01-01 05:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 267.
## # ... with 17 more variables: ws <dbl>, ceil_hgt <dbl>, visibility <dbl>,
## # air_temp <dbl>, dew_point <dbl>, atmos_pres <dbl>, RH <dbl>,
## # cl_1 <dbl>, cl_1_height <dbl>, cl_2 <dbl>, cl_2_height <dbl>,
## # cl_3 <dbl>, cl_3_height <dbl>, precip_12 <dbl>, precip_6 <dbl>,
## # cl <dbl>, precip <dbl>
A função desc() permite a ordenação decrescente
## # A tibble: 6 x 26
## date usaf wban code station lat lon elev wd
## <dttm> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 2019-09-14 21:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.456 25 215.
## 2 2019-09-14 20:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 229.
## 3 2019-09-14 19:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 224.
## 4 2019-09-14 18:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 224.
## 5 2019-09-14 17:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 231.
## 6 2019-09-14 16:00:00 0377~ 99999 0377~ HEATHR~ 51.5 -0.457 25 207.
## # ... with 17 more variables: ws <dbl>, ceil_hgt <dbl>, visibility <dbl>,
## # air_temp <dbl>, dew_point <dbl>, atmos_pres <dbl>, RH <dbl>,
## # cl_1 <dbl>, cl_1_height <dbl>, cl_2 <dbl>, cl_2_height <dbl>,
## # cl_3 <dbl>, cl_3_height <dbl>, precip_12 <dbl>, precip_6 <dbl>,
## # cl <dbl>, precip <dbl>
group_by():A função group_by será bastante usada..
Quem conhece SQL pode estranhar um pouco o comportamento desta função, pois ela não agrupa os dados diminuindo o número de linhas imediatamente.
Mas veja que ela indica que há agrupamento
## # A tibble: 684 x 3
## # Groups: country [152]
## country date value
## * <chr> <chr> <dbl>
## 1 Albania 2012 29
## 2 Albania 2008 30
## 3 Algeria 2011 27.6
## 4 Angola 2008 42.7
## 5 Argentina 2017 40.6
## 6 Argentina 2016 42.4
## 7 Argentina 2014 41.4
## 8 Argentina 2013 41
## 9 Argentina 2012 41.2
## 10 Argentina 2011 42.3
## # ... with 674 more rows
group_by() (cont.):Para várias operações, entretanto, o agrupamento faz com que o comportamento seja diferente
Uma operação bastante usada é numerar as linhas de um tibble.
No tibble agrupado, essa operação acontece em cada grupo.
group_by() (cont.):As funções lag() e lead() funcionam dentro de cada grupo (o primeiro value de um grupo não acessa o valor do outro grupo com lag() .
group_by() (cont.):A função group_by só leva a uma sumarização, ou seja, só transforma o tibble em um tibble com o número de linhas igual ao número de grupos, quando executamos a função summarise()
maiores_temp_dia <- dados_heathrow %>%
group_by(date(date)) %>%
summarise(
maxima = max(air_temp),
minima = min(air_temp),
media = mean(air_temp)
)
datatable(maiores_temp_dia) %>%
formatRound(c("maxima", "minima", "media"), 1)A função top_n retorna os n maiores valores. Se o tibble estiver agrupado, pra cada grupo.
maiores_temp_dia <- dados_heathrow %>%
group_by(date(date)) %>%
top_n(1, air_temp) %>%
ungroup() %>%
mutate(
hora = hour(date),
estacao =
case_when(
month(date) %in% 1:3 ~ "Inverno",
month(date) %in% 7:9 ~ "Verão",
TRUE ~ "Outono/Primavera"
)
) %>%
select(hora, estacao, air_temp)
ggplot(maiores_temp_dia) +
geom_density( aes(x = hora, color = estacao )) +
theme_light()Até agora acessamos dados que estavam disponíveis em bibliotecas, mas muitas vezes encontramos dados em arquivos.
De modo geral, as funções da biblioteca readr são mas rápidas do que as da biblioteca base, e também mostram barra de progresso no console. É possível reconhecê-las pelo _ ao invés de .
O portal da CVM é uma das minas de ouro de dados
O código abaixo baixa os dados que ainda não estão na nossa base
existem <- tibble(arquivo = list.files("dados/fundos"))
salva <- function(dado){
endereco <- pull(dado, endereco)
arquivo <- pull(dado, arquivo)
print(endereco)
conteudo <- read_csv2(endereco)
write_csv(conteudo, paste0("dados/fundos/",arquivo))
}
baixa_faltantes <- tibble(data_dado = seq(ymd("2017-01-01"), by = "month", ymd(today()) )) %>%
mutate(data_formato = stamp_date("999912")(data_dado)) %>%
mutate(
endereco = paste0(
"http://dados.cvm.gov.br/dados/FI/DOC/INF_DIARIO/DADOS/",
"inf_diario_fi_",
data_formato,
".csv")) %>%
mutate(arquivo = paste("inf_diario_fi_",data_formato,".csv")) %>%
anti_join(existem, by = c("arquivo" = "arquivo")) %>%
select(-data_formato) %>%
group_by(data_dado) %>%
nest() %>%
mutate(data = map(data, salva ))
le_arquivo <- function(lista_arquivo){
arquivo <- pull(lista_arquivo, arquivo)
conteudo <- read_csv(arquivo)
conteudo
}
todos_os_fundos <- tibble(arquivo = list.files("dados/fundos")) %>%
mutate(arquivo = paste0("dados/fundos/",arquivo )) %>%
group_by(row_number()) %>%
nest() %>%
mutate(data = map(data, le_arquivo)) %>%
unnest()
head(todos_os_fundos)## # A tibble: 6 x 9
## # Groups: row_number() [1]
## `row_number()` CNPJ_FUNDO DT_COMPTC VL_TOTAL VL_QUOTA VL_PATRIM_LIQ
## <int> <chr> <date> <dbl> <dbl> <dbl>
## 1 1 00.017.02~ 2017-01-02 1.08e8 2.43e13 108099858
## 2 1 00.017.02~ 2017-01-03 1.08e8 2.43e13 108144909
## 3 1 00.017.02~ 2017-01-04 1.08e8 2.43e13 108188649
## 4 1 00.017.02~ 2017-01-05 1.08e8 2.43e13 108234509
## 5 1 00.017.02~ 2017-01-06 1.08e8 2.43e13 108278954
## 6 1 00.017.02~ 2017-01-09 1.08e8 2.43e13 108321610
## # ... with 3 more variables: CAPTC_DIA <dbl>, RESG_DIA <dbl>,
## # NR_COTST <dbl>
cadastro_fundos <- read_csv2("http://dados.cvm.gov.br/dados/FIE/CAD/DADOS/inf_cadastral_fie.csv", locale = locale(encoding = "latin1") )## # A tibble: 675 x 9
## # Groups: row_number() [33]
## `row_number()` CNPJ_FUNDO DT_COMPTC VL_TOTAL VL_QUOTA VL_PATRIM_LIQ
## <int> <chr> <date> <dbl> <dbl> <dbl>
## 1 1 07.455.50~ 2017-01-02 1.31e12 8.61e12 1312862006441
## 2 1 07.455.50~ 2017-01-03 1.31e12 8.62e12 1311291630745
## 3 1 07.455.50~ 2017-01-04 1.30e12 8.58e12 1305299654809
## 4 1 07.455.50~ 2017-01-05 1.29e12 8.55e12 1300213664841
## 5 1 07.455.50~ 2017-01-06 1.30e12 8.56e12 1301706718495
## 6 1 07.455.50~ 2017-01-09 1.30e12 8.55e12 1300644945751
## 7 1 07.455.50~ 2017-01-10 1.30e12 8.55e12 1300428226690
## 8 1 07.455.50~ 2017-01-11 1.30e12 8.53e12 1296492684946
## 9 1 07.455.50~ 2017-01-12 1.32e12 8.60e12 1332935151782
## 10 1 07.455.50~ 2017-01-13 1.33e12 8.61e12 1333437691636
## # ... with 665 more rows, and 3 more variables: CAPTC_DIA <dbl>,
## # RESG_DIA <dbl>, NR_COTST <dbl>
Uma página WEB pode ser representada por uma árvore de objetos, também chamada de DOM (Document Object Model).
Esta árvore de objetos é definida pelo conteúdo de linguagem html que existe na página (e pode ser modificado por scripts em javascript e definições de estilo do CSS).
Podem existir objetos de vários tipos em uma página: links, inputs de dados, tabelas, células de tabelas, parágrafos, cabeçalhos etc.
Para retirar da página web o conteúdo de que precisamos, temos que analisar como é esta árvore de objetos e que nós desta árvore nos interessam.
Imagine que queremos buscar dados na página de histórico de preços e taxas dos títulos brasileiros
A tecla F12 do Chrome nos permite ver a árvore DOM da página em que estamos navegando.
É possível clicar com o botão direito e inspecionar um elementos específico de forma a saber onde ele está na árvore e que tipo de elemento ele é (mesmo que você saiba pouco de html).
O mais importante é saber que uma tag html que define um elemento tem a sintaxe:
<tipo_elemento nome_atributo=valor_attributo>texto do elemento</tipo_elemento>
Mesmo sem saber hmtl, fica claro que queremos esse tal de atributo href dos tais elementos a seja lá o que diabos isso seja (a é um link e href é o destino do link).
A biblioteca rvest possibilita a extração destes elementos.
É possível caminhar pela árvore DOM até os nós desejados e atributos que queremos usando html_nodes e html_attr.
Munidos de uma função que faz download e salva um arquivo, podemos caminhar pelas planilhas e salvá-las
existem <- tibble(arquivo = list.files("dados/titulos"))
salva_planilha <- function(dado){
arquivo <- pull(dado, endereco)
destino <- pull(dado, name_in)
download.file(
arquivo,
paste0("dados/titulos/",destino,".xls" ),
mode = "wb" ##PRA ARQUIVOS BINÁRIOS,
)
}
links <- read_html("https://sisweb.tesouro.gov.br/apex/f?p=2031:2:0::::") %>%
html_nodes("body") %>%
html_nodes("a") %>%
html_attr("href") %>%
enframe(value = "endereco") %>%
filter(str_detect(endereco, "cosis/sistd/obtem_arquivo/")) %>%
mutate(destino = paste0(name,".xls")) %>%
anti_join(existem, by = c("destino" = "arquivo")) %>%
select(-destino) %>%
mutate(endereco = paste0("https://sisweb.tesouro.gov.br/apex/",endereco) ) %>%
mutate(name_in = name) %>%
group_by(name) %>%
nest() %>%
mutate(data = map(data, salva_planilha ))Agora Vamos organizar as planilhas que lemos do site do tesouro.
Vamos usar a biblioteca read_xl.
Precisamos ler todas as sheets de todos os arquivos em um diretório (onde baixamos os arquivos excel do site do tesouro).
A função abaixo lê as sheets de um arquivo.
le_sheets <- function(dados){
arquivo <- pull(dados, arquivo)
excel_sheets(paste0("dados/titulos/",arquivo))
}A função abaixo lê o conteúdo de cada sheet
Munidos destas duas funções, podemos guardar tudo em um só dataframe.
Primeiro, definindo as sheets a ler
sheets_pra_ler <- list.files("dados/titulos") %>%
enframe(value = "arquivo") %>%
mutate(arquivo_out = arquivo) %>%
group_by(name, arquivo_out) %>%
nest() %>%
mutate(data = map(data, le_sheets)) %>%
unnest() %>%
rename(
arquivo = arquivo_out,
sheet = data
)Depois lendo as sheets para um dataframe
sheets_lidas <- sheets_pra_ler %>%
mutate(titulo = str_extract(sheet,"[^[0-9]]*" )) %>%
mutate(vencimento = str_extract(sheet,"[0-9]{6}" )) %>%
mutate(vencimento = dmy(vencimento)) %>%
mutate(
arquivo_out = arquivo,
sheet_out = sheet
) %>%
group_by(name, titulo, vencimento, arquivo_out, sheet_out) %>%
nest() %>%
mutate(data = map(data, le_conteudo_sheet)) %>%
unnest() %>%
ungroup()Uma última arrumada
taxas_titulos <- sheets_lidas %>%
rename(
data = 6,
taxa_compra_manha = 7,
taxa_venda_manha = 8,
pu_compra_manha = 9,
pu_venda_manha = 10,
pu_base_manha = 11
) %>%
mutate(
data = if_else(
str_detect(data, "/"),
dmy(data),
as.numeric(data) + ymd("1899-12-31")
)
) %>%
mutate(
titulo = str_trim(titulo),
taxa_compra_manha = as.numeric(taxa_compra_manha),
taxa_venda_manha = as.numeric(taxa_venda_manha),
pu_compra_manha = as.numeric(pu_compra_manha),
pu_venda_manha = as.numeric(pu_venda_manha),
pu_base_manha = as.numeric(pu_base_manha)
) %>%
select(
titulo,
vencimento,
data,
taxa_compra_manha,
taxa_venda_manha,
pu_compra_manha,
pu_venda_manha,
pu_base_manha
) %>%
mutate(
titulo = if_else(
titulo == "NTN-B Principal",
"NTN-B Princ",
titulo
)
)Aí fica fácil fazer a análise que desejarmos
ntnb_2045 <- taxas_titulos %>%
filter(
titulo == "NTN-B Princ",
vencimento == ymd("2045-05-15")
) %>%
mutate(taxa = (taxa_compra_manha +taxa_venda_manha)/2 )
ggplot(ntnb_2045) +
geom_line(aes(x = data, y = taxa) ) +
scale_x_date(
date_breaks = "3 months",
limits = c(ymd("2016-12-01"),NA),
labels = date_format("%m/%y")
) +
scale_y_continuous(
labels = percent_format(accuracy = 0.1)
) +
labs(y = "NTN-B Principal 2045", x = "Data") +
theme_light()Nem todas as páginas são fáceis de ler.
A página que mostra os DIs na BMF, por exemplo é esquisita:
O nosso objeto de interesse aparece na ferramenta chamada por F12, mas não é encontrada pela rvest ao ler o HTML
Existem duas técnicas para o Web Scraping:
Simular a navegação num browser emulado (fora do escopo deste curso)
Interpretar páginas com base no conteúdo recebido
Na página que visualizamos da BMF, o conteúdo recebido inclui um script javascript que popula a tabela, por isso não conseguimos reconhecer o conteúdo da tabela de pronto, pois ela só é carregada pela execução do script.
Conseguimos, no entanto, extrair do script as informações de que precisamos
O código abaixo extrai da página as informações de que precisamos.
Para extrair as informações, ele usa expressões regulares.
Repare na função que silencia um possível erro. Este erro pode acontecer se passarmos um dia que não tem dados. Precisamos disso pois vamos buscar todas as datas possíveis.
Essa não é a melhor forma de tratar um erro deste tipo. Veremos mais adiante
cotacoes <- tibble(
id = 0:10,
cotacao = c(
"ajuste_ant",
"ajuste_corrig",
"preco_abert",
"preco_min",
"preco_max",
"preco_med",
"ult_preco",
"ajuste",
"var_pontos",
"ult_of_compra",
"ult_of_venda"
)
)
#QUEM INVENTOU ISSO?
siglas_mes <- tibble(
sigla_mes = c(
"F",
"G",
"H",
"J",
"K",
"M",
"N",
"Q",
"U",
"V",
"X",
"Z"
),
mes = 1:12
)
pagina <- NA
try(
{pagina <- read_html("http://www2.bmf.com.br/pages/portal/bmfbovespa/boletim1/SistemaPregao1.asp?pagetype=pop&caminho=Resumo%20Estat%EDstico%20-%20Sistema%20Preg%E3o&Data=10/01/2017&Mercadoria=DI1") %>%
html_nodes("script") %>%
extract2(13) %>%
html_text()}
,
silent = TRUE
)
linhas_impares <- str_extract_all(pagina, "MercFut1 \\+ '<td ALIGN=\"right\" CLASS=\"tabelaConteudo1\">[0-9.,]*") %>%
extract2(1) %>%
enframe() %>%
mutate(
ativo = (row_number()-1) %/% 11 * 2,
tipo_cotacao = (row_number() - 1) %% 11
)
linhas_pares <- str_extract_all(pagina, "MercFut1 \\+ '<td ALIGN=\"right\" CLASS=\"tabelaConteudo2\">[0-9.,]*") %>%
extract2(1) %>%
enframe() %>%
mutate(
ativo = (row_number()-1) %/% 11 * 2 + 1,
tipo_cotacao = (row_number() - 1) %% 11
)
linhas <- linhas_impares %>%
bind_rows(linhas_pares) %>%
arrange(ativo) %>%
mutate(valor = str_extract_all(value, ">[0-9.,]*")) %>%
mutate(valor = str_sub(valor, 2)) %>%
select(ativo, tipo_cotacao, valor)
ativos <- str_extract_all(pagina, "MercFut3 = MercFut3 \\+ '</tr><td ALIGN=\"center\" CLASS=\"tabelaConteudo[0-9]\">[A-Z][0-9][0-9]") %>%
extract2(1) %>%
enframe() %>%
mutate(
nome_ativo = str_sub(value,-3),
id = name - 1
) %>%
select(
id,
nome_ativo
)
linhas %<>% left_join(ativos, by = c("ativo" = "id")) %>%
select(nome_ativo, tipo_cotacao, valor) %>%
mutate(
sigla_mes = str_sub(nome_ativo, 1,1),
ano = as.numeric(str_sub(nome_ativo, 2,4)) + 2000
) %>%
left_join(cotacoes, by = c("tipo_cotacao" = "id") ) %>%
left_join(siglas_mes, by = c("sigla_mes")) %>%
mutate(vencimento = make_date(ano, mes, 1)) %>%
mutate(
valor = parse_number(
valor,
locale = locale(
decimal_mark = ",",
grouping_mark = "."
)
)
) %>%
select(
nome_ativo,
vencimento,
cotacao,
valor
)Agora vamos executar para todos os dias desde janeiro de 2017.
Preparamos a função…
le_uma_pagina_bmf <- function(dados){
data <- pull(dados, data_in) %>%
stamp_date("31/01/2017")(.)
pagina <- NA
try(
{pagina <- read_html(paste0("http://www2.bmf.com.br/pages/portal/bmfbovespa/boletim1/SistemaPregao1.asp?pagetype=pop&caminho=Resumo%20Estat%EDstico%20-%20Sistema%20Preg%E3o&Data=",data,"&Mercadoria=DI1")) %>%
html_nodes("script") %>%
extract2(13) %>%
html_text()}
,
silent = TRUE
)
if (!is.na(pagina)){
linhas_impares <- str_extract_all(pagina, "MercFut1 \\+ '<td ALIGN=\"right\" CLASS=\"tabelaConteudo1\">[0-9.,]*") %>%
extract2(1) %>%
enframe() %>%
mutate(
ativo = (row_number()-1) %/% 11 * 2,
tipo_cotacao = (row_number() - 1) %% 11
)
linhas_pares <- str_extract_all(pagina, "MercFut1 \\+ '<td ALIGN=\"right\" CLASS=\"tabelaConteudo2\">[0-9.,]*") %>%
extract2(1) %>%
enframe() %>%
mutate(
ativo = (row_number()-1) %/% 11 * 2 + 1,
tipo_cotacao = (row_number() - 1) %% 11
)
linhas <- linhas_impares %>%
bind_rows(linhas_pares) %>%
arrange(ativo) %>%
mutate(valor = str_extract_all(value, ">[0-9.,]*")) %>%
mutate(valor = str_sub(valor, 2)) %>%
select(ativo, tipo_cotacao, valor)
ativos <- str_extract_all(pagina, "MercFut3 = MercFut3 \\+ '</tr><td ALIGN=\"center\" CLASS=\"tabelaConteudo[0-9]\">[A-Z][0-9][0-9]") %>%
extract2(1) %>%
enframe() %>%
mutate(
nome_ativo = str_sub(value,-3),
id = name - 1
) %>%
select(
id,
nome_ativo
)
linhas %<>% left_join(ativos, by = c("ativo" = "id")) %>%
select(nome_ativo, tipo_cotacao, valor) %>%
mutate(
sigla_mes = str_sub(nome_ativo, 1,1),
ano = as.numeric(str_sub(nome_ativo, 2,4)) + 2000
) %>%
left_join(cotacoes, by = c("tipo_cotacao" = "id") ) %>%
left_join(siglas_mes, by = c("sigla_mes")) %>%
mutate(vencimento = make_date(ano, mes, 1)) %>%
mutate(
valor = parse_number(
valor,
locale = locale(
decimal_mark = ",",
grouping_mark = "."
)
)
) %>%
select(
nome_ativo,
vencimento,
cotacao,
valor
)
linhas
}
else
{
tibble(dia_inutil = TRUE )
}
}E executamos para todos os dias.
O dataframe com todos os dados ficou assim.
Veja como as funções da biblioteca kable e kableExtra dão mais controle na criação das tabelas.
Note como ele ainda não está “Tidy”. Por quê?
dados_todas_as_datas %>%
ungroup() %>%
filter(is.na(dia_inutil)) %>%
select(-dia_inutil, - name) %>%
head(n = 200) %>%
mutate(
data_out = stamp_date("31/12/2010")(data_out),
vencimento = stamp_date("12/%Y")(vencimento),
valor = number(valor, accuracy = 0.001, decimal.mark = ",", big.mark = ".")
) %>%
kable(
col.names =
c(
"Data",
"Ativo",
"Vencimento",
"Tipo Cotação",
"Cotação"
),
align =
c("l","l","l","l","r")
) %>%
kable_styling(
) %>%
row_spec(
seq(2, 200, 2),
background = "#eeeeee"
) | Data | Ativo | Vencimento | Tipo Cotação | Cotação |
|---|---|---|---|---|
| 02/01/2017 | F17 | 01/2017 | ajuste_ant | 99.999,980 |
| 02/01/2017 | F17 | 01/2017 | ajuste_corrig | 100.050,710 |
| 02/01/2017 | F17 | 01/2017 | preco_abert | 0,000 |
| 02/01/2017 | F17 | 01/2017 | preco_min | 0,000 |
| 02/01/2017 | F17 | 01/2017 | preco_max | 0,000 |
| 02/01/2017 | F17 | 01/2017 | preco_med | 0,000 |
| 02/01/2017 | F17 | 01/2017 | ult_preco | 0,000 |
| 02/01/2017 | F17 | 01/2017 | ajuste | 100.000,000 |
| 02/01/2017 | F17 | 01/2017 | var_pontos | 0,020 |
| 02/01/2017 | F17 | 01/2017 | ult_of_compra | 0,000 |
| 02/01/2017 | F17 | 01/2017 | ult_of_venda | 0,000 |
| 02/01/2017 | G17 | 02/2017 | ajuste_ant | 98.918,060 |
| 02/01/2017 | G17 | 02/2017 | ajuste_corrig | 13,280 |
| 02/01/2017 | G17 | 02/2017 | preco_abert | 13,270 |
| 02/01/2017 | G17 | 02/2017 | preco_min | 13,280 |
| 02/01/2017 | G17 | 02/2017 | preco_max | 13,272 |
| 02/01/2017 | G17 | 02/2017 | preco_med | 13,271 |
| 02/01/2017 | G17 | 02/2017 | ult_preco | 98.918,080 |
| 02/01/2017 | G17 | 02/2017 | ajuste | 0,020 |
| 02/01/2017 | G17 | 02/2017 | var_pontos | 13,271 |
| 02/01/2017 | G17 | 02/2017 | ult_of_compra | 13,274 |
| 02/01/2017 | G17 | 02/2017 | ult_of_venda | 97.013,860 |
| 02/01/2017 | H17 | 03/2017 | ajuste_ant | 98.058,480 |
| 02/01/2017 | H17 | 03/2017 | ajuste_corrig | 98.107,120 |
| 02/01/2017 | H17 | 03/2017 | preco_abert | 13,150 |
| 02/01/2017 | H17 | 03/2017 | preco_min | 13,150 |
| 02/01/2017 | H17 | 03/2017 | preco_max | 13,156 |
| 02/01/2017 | H17 | 03/2017 | preco_med | 13,154 |
| 02/01/2017 | H17 | 03/2017 | ult_preco | 13,155 |
| 02/01/2017 | H17 | 03/2017 | ajuste | 98.057,400 |
| 02/01/2017 | H17 | 03/2017 | var_pontos | 1,080 |
| 02/01/2017 | H17 | 03/2017 | ult_of_compra | 13,150 |
| 02/01/2017 | H17 | 03/2017 | ult_of_venda | 13,160 |
| 02/01/2017 | J17 | 04/2017 | ajuste_ant | 97.059,280 |
| 02/01/2017 | J17 | 04/2017 | ajuste_corrig | 12,900 |
| 02/01/2017 | J17 | 04/2017 | preco_abert | 12,885 |
| 02/01/2017 | J17 | 04/2017 | preco_min | 12,925 |
| 02/01/2017 | J17 | 04/2017 | preco_max | 12,906 |
| 02/01/2017 | J17 | 04/2017 | preco_med | 12,910 |
| 02/01/2017 | J17 | 04/2017 | ult_preco | 97.010,090 |
| 02/01/2017 | J17 | 04/2017 | ajuste | 3,770 |
| 02/01/2017 | J17 | 04/2017 | var_pontos | 12,900 |
| 02/01/2017 | J17 | 04/2017 | ult_of_compra | 12,910 |
| 02/01/2017 | J17 | 04/2017 | ult_of_venda | 95.282,740 |
| 02/01/2017 | K17 | 05/2017 | ajuste_ant | 96.220,720 |
| 02/01/2017 | K17 | 05/2017 | ajuste_corrig | 96.267,740 |
| 02/01/2017 | K17 | 05/2017 | preco_abert | 12,745 |
| 02/01/2017 | K17 | 05/2017 | preco_min | 12,735 |
| 02/01/2017 | K17 | 05/2017 | preco_max | 12,745 |
| 02/01/2017 | K17 | 05/2017 | preco_med | 12,741 |
| 02/01/2017 | K17 | 05/2017 | ult_preco | 12,740 |
| 02/01/2017 | K17 | 05/2017 | ajuste | 96.218,950 |
| 02/01/2017 | K17 | 05/2017 | var_pontos | 1,770 |
| 02/01/2017 | K17 | 05/2017 | ult_of_compra | 12,740 |
| 02/01/2017 | K17 | 05/2017 | ult_of_venda | 12,755 |
| 02/01/2017 | M17 | 06/2017 | ajuste_ant | 95.330,910 |
| 02/01/2017 | M17 | 06/2017 | ajuste_corrig | 12,550 |
| 02/01/2017 | M17 | 06/2017 | preco_abert | 12,550 |
| 02/01/2017 | M17 | 06/2017 | preco_min | 12,550 |
| 02/01/2017 | M17 | 06/2017 | preco_max | 12,550 |
| 02/01/2017 | M17 | 06/2017 | preco_med | 12,550 |
| 02/01/2017 | M17 | 06/2017 | ult_preco | 95.282,590 |
| 02/01/2017 | M17 | 06/2017 | ajuste | 0,150 |
| 02/01/2017 | M17 | 06/2017 | var_pontos | 12,550 |
| 02/01/2017 | M17 | 06/2017 | ult_of_compra | 0,000 |
| 02/01/2017 | M17 | 06/2017 | ult_of_venda | 93.605,300 |
| 02/01/2017 | N17 | 07/2017 | ajuste_ant | 94.410,120 |
| 02/01/2017 | N17 | 07/2017 | ajuste_corrig | 94.481,010 |
| 02/01/2017 | N17 | 07/2017 | preco_abert | 12,380 |
| 02/01/2017 | N17 | 07/2017 | preco_min | 12,340 |
| 02/01/2017 | N17 | 07/2017 | preco_max | 12,400 |
| 02/01/2017 | N17 | 07/2017 | preco_med | 12,349 |
| 02/01/2017 | N17 | 07/2017 | ult_preco | 12,340 |
| 02/01/2017 | N17 | 07/2017 | ajuste | 94.433,120 |
| 02/01/2017 | N17 | 07/2017 | var_pontos | 23,000 |
| 02/01/2017 | N17 | 07/2017 | ult_of_compra | 12,335 |
| 02/01/2017 | N17 | 07/2017 | ult_of_venda | 12,350 |
| 02/01/2017 | Q17 | 08/2017 | ajuste_ant | 93.674,050 |
| 02/01/2017 | Q17 | 08/2017 | ajuste_corrig | 12,185 |
| 02/01/2017 | Q17 | 08/2017 | preco_abert | 12,160 |
| 02/01/2017 | Q17 | 08/2017 | preco_min | 12,185 |
| 02/01/2017 | Q17 | 08/2017 | preco_max | 12,161 |
| 02/01/2017 | Q17 | 08/2017 | preco_med | 12,160 |
| 02/01/2017 | Q17 | 08/2017 | ult_preco | 93.626,570 |
| 02/01/2017 | Q17 | 08/2017 | ajuste | 21,270 |
| 02/01/2017 | Q17 | 08/2017 | var_pontos | 0,000 |
| 02/01/2017 | Q17 | 08/2017 | ult_of_compra | 0,000 |
| 02/01/2017 | Q17 | 08/2017 | ult_of_venda | 91.983,900 |
| 02/01/2017 | U17 | 09/2017 | ajuste_ant | 92.722,560 |
| 02/01/2017 | U17 | 09/2017 | ajuste_corrig | 92.798,300 |
| 02/01/2017 | U17 | 09/2017 | preco_abert | 11,935 |
| 02/01/2017 | U17 | 09/2017 | preco_min | 11,935 |
| 02/01/2017 | U17 | 09/2017 | preco_max | 11,935 |
| 02/01/2017 | U17 | 09/2017 | preco_med | 11,935 |
| 02/01/2017 | U17 | 09/2017 | ult_preco | 11,935 |
| 02/01/2017 | U17 | 09/2017 | ajuste | 92.751,270 |
| 02/01/2017 | U17 | 09/2017 | var_pontos | 28,710 |
| 02/01/2017 | U17 | 09/2017 | ult_of_compra | 0,000 |
| 02/01/2017 | U17 | 09/2017 | ult_of_venda | 0,000 |
| 02/01/2017 | V17 | 10/2017 | ajuste_ant | 92.043,710 |
| 02/01/2017 | V17 | 10/2017 | ajuste_corrig | 11,850 |
| 02/01/2017 | V17 | 10/2017 | preco_abert | 11,810 |
| 02/01/2017 | V17 | 10/2017 | preco_min | 11,850 |
| 02/01/2017 | V17 | 10/2017 | preco_max | 11,827 |
| 02/01/2017 | V17 | 10/2017 | preco_med | 11,825 |
| 02/01/2017 | V17 | 10/2017 | ult_preco | 91.997,060 |
| 02/01/2017 | V17 | 10/2017 | ajuste | 13,160 |
| 02/01/2017 | V17 | 10/2017 | var_pontos | 11,820 |
| 02/01/2017 | V17 | 10/2017 | ult_of_compra | 11,825 |
| 02/01/2017 | V17 | 10/2017 | ult_of_venda | 90.483,600 |
| 02/01/2017 | X17 | 11/2017 | ajuste_ant | 91.212,090 |
| 02/01/2017 | X17 | 11/2017 | ajuste_corrig | 91.295,710 |
| 02/01/2017 | X17 | 11/2017 | preco_abert | 11,650 |
| 02/01/2017 | X17 | 11/2017 | preco_min | 11,650 |
| 02/01/2017 | X17 | 11/2017 | preco_max | 11,650 |
| 02/01/2017 | X17 | 11/2017 | preco_med | 11,650 |
| 02/01/2017 | X17 | 11/2017 | ult_preco | 11,650 |
| 02/01/2017 | X17 | 11/2017 | ajuste | 91.249,440 |
| 02/01/2017 | X17 | 11/2017 | var_pontos | 37,350 |
| 02/01/2017 | X17 | 11/2017 | ult_of_compra | 0,000 |
| 02/01/2017 | X17 | 11/2017 | ult_of_venda | 0,000 |
| 02/01/2017 | Z17 | 12/2017 | ajuste_ant | 90.589,120 |
| 02/01/2017 | Z17 | 12/2017 | ajuste_corrig | 11,540 |
| 02/01/2017 | Z17 | 12/2017 | preco_abert | 11,540 |
| 02/01/2017 | Z17 | 12/2017 | preco_min | 11,540 |
| 02/01/2017 | Z17 | 12/2017 | preco_max | 11,540 |
| 02/01/2017 | Z17 | 12/2017 | preco_med | 11,540 |
| 02/01/2017 | Z17 | 12/2017 | ult_preco | 90.543,210 |
| 02/01/2017 | Z17 | 12/2017 | ajuste | 59,610 |
| 02/01/2017 | Z17 | 12/2017 | var_pontos | 0,000 |
| 02/01/2017 | Z17 | 12/2017 | ult_of_compra | 0,000 |
| 02/01/2017 | Z17 | 12/2017 | ult_of_venda | 87.645,570 |
| 02/01/2017 | F18 | 01/2018 | ajuste_ant | 89.783,790 |
| 02/01/2017 | F18 | 01/2018 | ajuste_corrig | 89.887,770 |
| 02/01/2017 | F18 | 01/2018 | preco_abert | 11,510 |
| 02/01/2017 | F18 | 01/2018 | preco_min | 11,435 |
| 02/01/2017 | F18 | 01/2018 | preco_max | 11,510 |
| 02/01/2017 | F18 | 01/2018 | preco_med | 11,459 |
| 02/01/2017 | F18 | 01/2018 | ult_preco | 11,440 |
| 02/01/2017 | F18 | 01/2018 | ajuste | 89.842,210 |
| 02/01/2017 | F18 | 01/2018 | var_pontos | 58,420 |
| 02/01/2017 | F18 | 01/2018 | ult_of_compra | 11,440 |
| 02/01/2017 | F18 | 01/2018 | ult_of_venda | 11,450 |
| 02/01/2017 | J18 | 04/2018 | ajuste_ant | 87.782,490 |
| 02/01/2017 | J18 | 04/2018 | ajuste_corrig | 11,250 |
| 02/01/2017 | J18 | 04/2018 | preco_abert | 11,210 |
| 02/01/2017 | J18 | 04/2018 | preco_min | 11,250 |
| 02/01/2017 | J18 | 04/2018 | preco_max | 11,225 |
| 02/01/2017 | J18 | 04/2018 | preco_med | 11,220 |
| 02/01/2017 | J18 | 04/2018 | ult_preco | 87.738,000 |
| 02/01/2017 | J18 | 04/2018 | ajuste | 92,430 |
| 02/01/2017 | J18 | 04/2018 | var_pontos | 0,000 |
| 02/01/2017 | J18 | 04/2018 | ult_of_compra | 0,000 |
| 02/01/2017 | J18 | 04/2018 | ult_of_venda | 83.304,290 |
| 02/01/2017 | N18 | 07/2018 | ajuste_ant | 85.496,480 |
| 02/01/2017 | N18 | 07/2018 | ajuste_corrig | 85.650,460 |
| 02/01/2017 | N18 | 07/2018 | preco_abert | 11,120 |
| 02/01/2017 | N18 | 07/2018 | preco_min | 11,060 |
| 02/01/2017 | N18 | 07/2018 | preco_max | 11,130 |
| 02/01/2017 | N18 | 07/2018 | preco_med | 11,085 |
| 02/01/2017 | N18 | 07/2018 | ult_preco | 11,080 |
| 02/01/2017 | N18 | 07/2018 | ajuste | 85.607,050 |
| 02/01/2017 | N18 | 07/2018 | var_pontos | 110,570 |
| 02/01/2017 | N18 | 07/2018 | ult_of_compra | 11,060 |
| 02/01/2017 | N18 | 07/2018 | ult_of_venda | 11,080 |
| 02/01/2017 | V18 | 10/2018 | ajuste_ant | 83.488,070 |
| 02/01/2017 | V18 | 10/2018 | ajuste_corrig | 11,050 |
| 02/01/2017 | V18 | 10/2018 | preco_abert | 11,000 |
| 02/01/2017 | V18 | 10/2018 | preco_min | 11,050 |
| 02/01/2017 | V18 | 10/2018 | preco_max | 11,015 |
| 02/01/2017 | V18 | 10/2018 | preco_med | 11,010 |
| 02/01/2017 | V18 | 10/2018 | ult_preco | 83.445,750 |
| 02/01/2017 | V18 | 10/2018 | ajuste | 141,460 |
| 02/01/2017 | V18 | 10/2018 | var_pontos | 0,000 |
| 02/01/2017 | V18 | 10/2018 | ult_of_compra | 11,010 |
| 02/01/2017 | V18 | 10/2018 | ult_of_venda | 79.189,040 |
| 02/01/2017 | F19 | 01/2019 | ajuste_ant | 81.272,780 |
| 02/01/2017 | F19 | 01/2019 | ajuste_corrig | 81.415,280 |
| 02/01/2017 | F19 | 01/2019 | preco_abert | 11,000 |
| 02/01/2017 | F19 | 01/2019 | preco_min | 10,930 |
| 02/01/2017 | F19 | 01/2019 | preco_max | 11,030 |
| 02/01/2017 | F19 | 01/2019 | preco_med | 10,968 |
| 02/01/2017 | F19 | 01/2019 | ult_preco | 10,950 |
| 02/01/2017 | F19 | 01/2019 | ajuste | 81.374,020 |
| 02/01/2017 | F19 | 01/2019 | var_pontos | 101,240 |
| 02/01/2017 | F19 | 01/2019 | ult_of_compra | 10,940 |
| 02/01/2017 | F19 | 01/2019 | ult_of_venda | 10,950 |
| 02/01/2017 | J19 | 04/2019 | ajuste_ant | 79.341,870 |
| 02/01/2017 | J19 | 04/2019 | ajuste_corrig | 11,010 |
| 02/01/2017 | J19 | 04/2019 | preco_abert | 10,970 |
| 02/01/2017 | J19 | 04/2019 | preco_min | 11,010 |
| 02/01/2017 | J19 | 04/2019 | preco_max | 11,002 |
| 02/01/2017 | J19 | 04/2019 | preco_med | 10,980 |
| 02/01/2017 | J19 | 04/2019 | ult_preco | 79.301,660 |
| 02/01/2017 | J19 | 04/2019 | ajuste | 112,620 |
| 02/01/2017 | J19 | 04/2019 | var_pontos | 0,000 |
| 02/01/2017 | J19 | 04/2019 | ult_of_compra | 0,000 |
| 02/01/2017 | J19 | 04/2019 | ult_of_venda | 74.943,830 |
| 02/01/2017 | N19 | 07/2019 | ajuste_ant | 77.133,610 |
| 02/01/2017 | N19 | 07/2019 | ajuste_corrig | 77.313,440 |
Reparamos que o dataframe no slide anterior não está “Tidy”, ou seja não está de forma que cada linha represente um evento e cada coluna represente um atributo do evento.
Para nós, neste caso, um evento é formado por todas as informações de um ativo em um dia e não uma só das informações de um ativo em um dia.
Isso porque é extremamente comum fazermos contas com mais de uma informação do ativo em um dia (máxima - mínima, por exemplo)
O pacote Tidyr ajuda a arrumar os data frames dessas formas. O hex sticker dele é bem explicativo.
Os nomes das principais funções mudaram em setembro de 2019 (quando saiu a versão 1.0.0). Antes se chamavam gather() e spread() e agora se chamam pivot_wider() e pivot_longer(), o que é mais intuitivo.
O nosso data frame tem cada tipo de cotação em cada linha e gostaríamos que essas linhas fossem transformadas em colunas.
A função que faz isso se chama pivot_wider()
Seus parâmetros mais usados são:
data, que é o data frame a ser tratado
names_from, que é o atributo de onde vêm os nomes para os novos atributos
values_from, o atributo de onde vêm os valores dos novos atributos
## # A tibble: 6 x 17
## data_out name dia_inutil nome_ativo vencimento `NA` ajuste_ant
## <date> <int> <lgl> <chr> <date> <dbl> <dbl>
## 1 2017-01-01 1 TRUE <NA> NA NA NA
## 2 2017-01-02 2 NA F17 2017-01-01 NA 100000.
## 3 2017-01-02 2 NA G17 2017-02-01 NA 98918.
## 4 2017-01-02 2 NA H17 2017-03-01 NA 98058.
## 5 2017-01-02 2 NA J17 2017-04-01 NA 97059.
## 6 2017-01-02 2 NA K17 2017-05-01 NA 96221.
## # ... with 10 more variables: ajuste_corrig <dbl>, preco_abert <dbl>,
## # preco_min <dbl>, preco_max <dbl>, preco_med <dbl>, ult_preco <dbl>,
## # ajuste <dbl>, var_pontos <dbl>, ult_of_compra <dbl>,
## # ult_of_venda <dbl>
manobras com vars, starts_with, num_range etc
n_simul <- 10000
n_questoes <- 240
min_aprovacao <- 0.6
n_aprovado <- 240 * min_aprovacao
prob_questao <- 0.2
estimar_chance <- function(...){
print("aqui")
fracao_eliminar_questoes <- as.vector(...)
#definindo o número de questões
n_questoes_cada_elimina <- t(rmultinom(n_simul, size = n_questoes, fracao_eliminar_questoes))
probs_quando_elimina <- 1/(5:1)
acertos_concatenados <-
rbinom(
n = n_simul * 5 ,
size = as.vector(t(n_questoes_cada_elimina)),
prob = probs_quando_elimina
)
matriz_acertos <- matrix(acertos_concatenados, byrow = TRUE, nrow = n_simul )
acertos <- rowSums(matriz_acertos)
sum(acertos > n_aprovado)/n_simul
}
#definindo a chance podermos eliminar 0, 1, 2, ... 4 alternativas
resultados <- RandVec(n = 5, m = 100) %>%
.$RandVecOutput %>%
t() %>%
as_tibble() %>%
mutate(id = row_number()) %>%
group_by(id) %>%
nest() %>%
mutate(data_fica = data) %>%
mutate(data = map(data, estimar_chance) ) %>%
unnest()## Warning: `as_tibble.matrix()` requires a matrix with column names or a `.name_repair` argument. Using compatibility `.name_repair`.
## This warning is displayed once per session.
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## [1] "aqui"
## Warning: `cols` is now required.
## Please use `cols = c(data, data_fica)`